//
//  GAKKIBaseWebViewController.m
//  GANGAIKit
//
//  Created by fh on 2019/11/15.
//  Copyright © 2019 cashchina. All rights reserved.
//

#import "GAKKIBaseWebViewController.h"
#import <KVOController/KVOController.h>

@interface WeakScriptMessageDelegate : NSObject<WKScriptMessageHandler>
@property (nonatomic, weak) id<WKScriptMessageHandler> scriptDelegate;
- (instancetype)initWithDelegate:(id<WKScriptMessageHandler>)scriptDelegate;
@end

@implementation WeakScriptMessageDelegate
- (instancetype)initWithDelegate:(id<WKScriptMessageHandler>)scriptDelegate{
    self = [super init];
    if (self) {
        _scriptDelegate = scriptDelegate;
    }
    return self;
}
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{
    [self.scriptDelegate userContentController:userContentController didReceiveScriptMessage:message];
}
- (void)dealloc{
#ifdef DEBUG
    DBLog(@"\n ======++++++ %@ 销毁了 ++++++===== \n",[self class])
#endif
}
@end

@interface GAKKIBaseWebViewController () {
    /** KVOController 监听数据 */
    FBKVOController *_KVOController;
}
/** webView */
@property (nonatomic, readwrite, strong) WKWebView *webView;
/** webView配置:暂时没使用 */
@property (nonatomic, readwrite, strong) WKWebViewConfiguration *configuration;
/** 进度条 */
@property (nonatomic, readwrite, strong) UIProgressView *progressView;
/** 返回按钮 */
@property (nonatomic, readwrite, strong) UIBarButtonItem *backItem;
/** 关闭按钮 （点击关闭按钮退出webView） */
@property (nonatomic, readwrite, strong) UIBarButtonItem *closeItem;

@end

@implementation GAKKIBaseWebViewController

#pragma mark - Life
+ (instancetype)new {
    return [super new];
}
- (instancetype)init {
    if (self = [super init]) {
        [self defaultInitData];
    }
    return self;
}
- (instancetype)initWithParams:(NSDictionary *)params {
    self = [super initWithParams:params];
    if (self) {
        [self defaultInitData];
    }
    return self;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    //    self.navigationItem.leftBarButtonItem = self.backItem;
    if (self.shouldAutoLoadRequestUrl) {
        [self innerFixedError];
    }
    [self innerSetupSubViews];
    [self observeDataChange];
}

- (void)viewDidDisappear:(BOOL)animated {
    [super viewDidDisappear:animated];
    //    [self releaseResource];
}

#pragma mark - Event
- (void)backItemDidClicked { /// 返回按钮事件处理
    /// 可以返回到上一个网页，就返回到上一个网页
    if (self.webView.canGoBack) {
        [self.webView goBack];
    }else{/// 不能返回上一个网页，就返回到上一个界面
        /// 判断 是Push还是Present进来的，
        [self closeItemDidClicked];
    }
}
- (void)closeItemDidClicked {
    // 释放资源
    [self releaseResource];
    /// 判断 是Push还是Present进来的
    if (self.navigationController != self.presentingViewController || [self.presentationController isKindOfClass:[UINavigationController class]]) {
        [self.navigationController popViewControllerAnimated:YES];
    } else {
        [self dismissViewControllerAnimated:YES completion:NULL]; // self.presentingViewController
    }
}
#pragma mark - Public
- (void)loadRequestUrl {
    [self innerFixedError];
}
#pragma mark - Private
- (void)defaultInitData {
    _shouldDisableWebViewClose = NO;
    _shouldDisableWebViewTitle = YES;
    _shouldAutoLoadRequestUrl = YES;
    _navigationBarHeight = 0; // kApplicationTopBarHeight
}
- (void)releaseResource {
    /// remove observer ,otherwise will crash
    [_webView stopLoading];
    /// Fixed Bug :移除掉JS调用OC的方法，否则循环引用
    for (NSString * name in _messageHandlers) {
        [_webView.configuration.userContentController removeScriptMessageHandlerForName:name];
    }
    
    [_webView stopLoading];
//    _webView.scrollView.delegate = nil;
    _webView.navigationDelegate = nil;
    _webView.UIDelegate = nil;
    _webView = nil;
}

- (void)innerSetupSubViews {
    
    [self.view addSubview:self.webView];
    [self layoutWebViewFrame];
    
    self.webView.scrollView.contentInset = self.contentInset;
#ifdef __IPHONE_11_0
    // 适配 iPhone X + iOS 11，去掉安全区域
    if (@available(iOS 11.0, *)) {
        kAdjustsScrollViewInsets_Never(self.webView.scrollView);
    }
#endif
    // Fixed Bug ： 将进度条加载在当前控制器上面
    [self.view addSubview:self.progressView];
    [self.progressView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.and.right.equalTo(self.view);
        make.height.mas_equalTo(2);
        make.top.equalTo(self.view).with.offset(self.navigationBarHeight);
    }];
}

- (void)layoutWebViewFrame {
    [self.webView mas_remakeConstraints:^(MASConstraintMaker *make) {
        make.edges.equalTo(self.view);
    }];
}

- (void)observeDataChange {
    // 监听数据
    _KVOController = [FBKVOController controllerWithObserver:self];
    WeakSelf;
    // binding self.avatarUrlString
    [_KVOController observe:weakSelf.webView keyPath:@"title" options:NSKeyValueObservingOptionInitial|NSKeyValueObservingOptionNew block:^(id  _Nullable observer, id  _Nonnull object, NSDictionary<NSString *,id> * _Nonnull change) {
        // Fixed: 这里只设置导航栏的title 以免self.title 设置了tabBarItem.title
        if (!weakSelf.shouldDisableWebViewTitle) {
            weakSelf.navigationItem.title = weakSelf.webView.title;
        }
    }];
    
    [_KVOController observe:weakSelf.webView keyPath:@"loading" options:NSKeyValueObservingOptionInitial|NSKeyValueObservingOptionNew block:^(id  _Nullable observer, id  _Nonnull object, NSDictionary<NSString *,id> * _Nonnull change) {
        
    }];
    
    [_KVOController observe:weakSelf.webView keyPath:@"estimatedProgress" options:NSKeyValueObservingOptionInitial|NSKeyValueObservingOptionNew block:^(id  _Nullable observer, id  _Nonnull object, NSDictionary<NSString *,id> * _Nonnull change) {
        [weakSelf.progressView setAlpha:1.0f];
        [weakSelf.progressView setProgress:weakSelf.webView.estimatedProgress animated:YES];
        if(weakSelf.webView.estimatedProgress >= 1.0f) {
            [UIView animateWithDuration:0.3 delay:0.3 options:UIViewAnimationOptionCurveEaseOut animations:^{
                [weakSelf.progressView setAlpha:0.0f];
            } completion:^(BOOL finished) {
                [weakSelf.progressView setProgress:0.0f animated:NO];
            }];
        }
    }];
}

- (void)innerFixedError {
    // 容错处理
    if (!kStringIsEmpty(self.requestUrl) && !self.isLocalFile)  {    /// 网络
        // 格式化含有中文的url
        self.requestUrl =  (NSString *)CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef)self.requestUrl, (CFStringRef)@"!$&'()*+,-./:;=?@_~%#[]", nil, kCFStringEncodingUTF8));
        NSMutableURLRequest * request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:self.requestUrl] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:20.0];  // NSURLRequestUseProtocolCachePolicy  NSURLRequestReloadIgnoringCacheData
        // 加载请求数据
        [self.webView loadRequest:request];
    }else if (!kStringIsEmpty(self.requestUrl) && self.isLocalFile){ /// 本地
        // 本地分 ios9.0以下 和 ios9.0以上处理方式
        // https://www.jianshu.com/p/ccb421c85b2e
        // https://blog.csdn.net/xinshou_caizhu/article/details/72614584
        // https://blog.csdn.net/wojiaoqiaoxiaoqiao/article/details/79876904
        NSURL *fileURL = [NSURL fileURLWithPath:self.requestUrl];
        if ([[UIDevice currentDevice].systemVersion floatValue] >= 9.0) {
            // iOS9. One year later things are OK.
//            [self.webView loadFileURL:fileURL allowingReadAccessToURL:fileURL];
            if (@available(iOS 9.0, *)) {
                [self.webView loadFileURL:fileURL allowingReadAccessToURL:fileURL];
            } else {
                // Fallback on earlier versions
                fileURL = [self innerFileURLForBuggyWKWebView8:fileURL];
                NSURLRequest *request = [NSURLRequest requestWithURL:fileURL];
                [self.webView loadRequest:request];
            }
        } else {
            // iOS8. Things can be workaround-ed
            //  Brave people can do just this
            fileURL = [self innerFileURLForBuggyWKWebView8:fileURL];
            NSURLRequest *request = [NSURLRequest requestWithURL:fileURL];
            [self.webView loadRequest:request];
        }
    }
    // 注册 JS调用OC的方法
    for (NSString * name in self.messageHandlers) {
        [self.webView.configuration.userContentController addScriptMessageHandler:[[WeakScriptMessageDelegate alloc] initWithDelegate:self] name:name];
    }
}
// 9.0以下将文件夹copy到tmp目录
- (NSURL *)innerFileURLForBuggyWKWebView8:(NSURL *)fileURL {
    NSError *error = nil;
    if (!fileURL.fileURL || ![fileURL checkResourceIsReachableAndReturnError:&error]) {
        return nil;
    }
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSURL *temDirURL = [NSURL fileURLWithPath:NSTemporaryDirectory()];
    [fileManager createDirectoryAtURL:temDirURL withIntermediateDirectories:YES attributes:nil error:&error];
    NSURL *dstURL = [temDirURL URLByAppendingPathComponent:fileURL.lastPathComponent];
    [fileManager removeItemAtURL:dstURL error:&error];
    [fileManager copyItemAtURL:fileURL toURL:dstURL error:&error];
    return dstURL;
}

#pragma mark - WKScriptMessageHandler
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
    /// js call OC function
#ifdef DEBUG
    DBLog(@"------>>> JS--Call--OC <<<------\n message.name:  %@\n message.body:  %@",message.name, message.body);
#endif
}

#pragma mark - WKNavigationDelegate
/// 内容开始返回时调用
- (void)webView:(WKWebView *)webView didCommitNavigation:(null_unspecified WKNavigation *)navigation {
    /// 不显示关闭按钮
    if(self.shouldDisableWebViewClose) {
        return;
    }
    UIBarButtonItem *backItem = self.navigationItem.leftBarButtonItems.firstObject;
    if (backItem) {
        if ([self.webView canGoBack]) {
            [self.navigationItem setLeftBarButtonItems:@[backItem, self.closeItem]];
        } else {
            [self.navigationItem setLeftBarButtonItems:@[backItem]];
        }
        [self.navigationItem.leftBarButtonItems.lastObject setTintColor:[UIColor whiteColor]];
    }
}

// 导航完成时，会回调（也就是页面载入完成了）
- (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation {
    
}
// 导航失败时会回调
- (void)webView:(WKWebView *)webView didFailNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error {
    if (error) {
       
    }
}
// 失败时加载空视图
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(null_unspecified WKNavigation *)navigation withError:(nonnull NSError *)error {
    NSString *errorDes = nil;
    if (error.code ==  NSURLErrorCannotFindHost) {
        errorDes = [NSString stringWithFormat:@"位于%@的网页加载失败,不能找到主机!",self.requestUrl];
    }
    if (error.code == NSURLErrorCannotConnectToHost) {
        errorDes = [NSString stringWithFormat:@"位于%@的网页加载失败,链接主机失败!",self.requestUrl];
    }
    if (error.code == NSURLErrorNotConnectedToInternet) {
        errorDes = [NSString stringWithFormat:@"位于%@的网页加载失败,不能连接到互联网!",self.requestUrl];
    }
    if (error.code == NSURLErrorTimedOut) {
        errorDes = [NSString stringWithFormat:@"位于%@的网页加载失败,请求超时!",self.requestUrl];
    }
    if (error) {
#ifdef DEBUG
        DBLog(@"网页加载错误信息: %@ - %@",error,errorDes);
#endif
    }
}

// 在发送请求之前，决定是否跳转,子类需要复写
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
    decisionHandler(WKNavigationActionPolicyAllow);
  
}

- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler {
    NSHTTPURLResponse *response = (NSHTTPURLResponse *)navigationResponse.response;
    if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
        NSArray *cookies =[NSHTTPCookie cookiesWithResponseHeaderFields:[response allHeaderFields] forURL:response.URL];
        for (NSHTTPCookie *cookie in cookies) {
            [[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookie:cookie];
        }
    }
    decisionHandler(WKNavigationResponsePolicyAllow);
}


- (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *__nullable credential))completionHandler {
    NSURLCredential *cred = [[NSURLCredential alloc] initWithTrust:challenge.protectionSpace.serverTrust];
    completionHandler(NSURLSessionAuthChallengeUseCredential, cred);
}

#pragma mark - WKUIDelegate
- (nullable WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures {
    /// CoderMike Fixed : 解决点击网页的链接 不跳转的Bug。
    WKFrameInfo *frameInfo = navigationAction.targetFrame;
    if (![frameInfo isMainFrame]) {
        [webView loadRequest:navigationAction.request];
    }
    return nil;
}
//*/

#pragma mark - RunJavaScript
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler {
    //    [NSObject mh_showAlertViewWithTitle:nil message:message confirmTitle:@"我知道了"];
//#warning mark - 这里后面封装弹框视图
    completionHandler();
}

- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler {
    completionHandler(YES);
}

- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * __nullable result))completionHandler {
    completionHandler(defaultText);
}


#pragma mark - UIScrollViewDelegate
/*
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
    /// CoderMikeHe Fixed Bug ： 调整webView滚动速率
    /// https://www.cnblogs.com/NSong/p/6489802.html
    /// https://github.com/ShingoFukuyama/WKWebViewTips
    scrollView.decelerationRate = UIScrollViewDecelerationRateNormal;
}
//*/

#pragma mark - Setter and getter
- (WKWebView *)webView {
    if (!_webView) {
        // 初始化WebView
        _webView = [[WKWebView alloc] initWithFrame:CGRectZero];
        //        _webView = [[WKWebView alloc] initWithFrame:self.view.bounds configuration:self.configuration]; // 要使用配置的话使用该方法初始化
        _webView.navigationDelegate = self;
        _webView.UIDelegate = self;
        _webView.scrollView.showsVerticalScrollIndicator = NO;
        // 设置代理
//        _webView.scrollView.delegate = self;
        
        // Fixed: 切记 lightempty_ios 是前端跟H5商量的结果，请勿修改。
        //        NSString *userAgent = @"wechat_ios";
        // 设置请求的User-Agent信息中应用程序名称 iOS9后可用 以下方法二选一
        if ((kiOSVersion >= 9.0)) {
            //            _webView.customUserAgent = userAgent;
        }
        // oc调用js
        [_webView evaluateJavaScript:@"navigator.userAgent" completionHandler:^(id result, NSError *error) {
            DBLog(@"客户端: %@", result);
        }];
    }
    return _webView;
}
- (WKWebViewConfiguration *)configuration {
    if (!_configuration) {
        // 注册JS
        WKUserContentController *userContentController = [[WKUserContentController alloc] init];
        // Fixed : 自适应屏幕宽度js
        NSString *jsString = @"var meta = document.createElement('meta'); meta.setAttribute('name', 'viewport'); meta.setAttribute('content', 'width=device-width'); document.getElementsByTagName('head')[0].appendChild(meta);";
        WKUserScript *userScript = [[WKUserScript alloc] initWithSource:jsString injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:YES];
        // 添加自适应屏幕宽度js调用的方法
        [userContentController addUserScript:userScript];
        
        _configuration = [[WKWebViewConfiguration alloc] init];
        // 赋值userContentController
        _configuration.userContentController = userContentController;
        // 字体
        //        _configuration.preferences.minimumFontSize = 10;
        // 在iOS上默认为NO，表示不能自动通过窗口打开
        _configuration.preferences.javaScriptCanOpenWindowsAutomatically = YES;
        
        /*
        // 把手动播放设置NO ios(8.0, 9.0)
        if (kiOS9VerstionLater) {
            // 9.0以后的版本
            // 允许视频播放
            _configuration.allowsAirPlayForMediaPlayback = YES;
            _configuration.requiresUserActionForMediaPlayback = YES;
            if (kiOS10VerstionLater) {
                // 10.0以后的版本
                _configuration.mediaTypesRequiringUserActionForPlayback = WKAudiovisualMediaTypeAll;
            }
        }else{
            // 9.0之前的版本
            _configuration.mediaPlaybackRequiresUserAction = YES;
            _configuration.mediaPlaybackAllowsAirPlay = YES;
        }
        //*/
        

        // 把手动播放设置NO ios(8.0, 9.0)
        // 10.0以后的版本
        if (@available(iOS 10.0, *)) {
            // 允许视频播放
            _configuration.mediaTypesRequiringUserActionForPlayback = WKAudiovisualMediaTypeAll;
        } else {
            // Fallback on earlier versions
            if (@available(iOS 9.0, *)) {
                // 允许视频播放
                _configuration.allowsAirPlayForMediaPlayback = YES;
                _configuration.requiresUserActionForMediaPlayback = YES;
            } else {
                // 9.0之前的版本
                _configuration.mediaPlaybackRequiresUserAction = YES;
                _configuration.mediaPlaybackAllowsAirPlay = YES;
            }
        }
        
        // 是否允许内联(YES)或使用本机全屏控制器(NO)，默认是NO。
        _configuration.allowsInlineMediaPlayback = YES;
        // 允许可以与网页交互，选择视图
        _configuration.selectionGranularity = WKSelectionGranularityDynamic;
        // web内容处理池
        _configuration.processPool = [[WKProcessPool alloc] init];
        // 是否等待内容全部加到内存中再去渲染webView
        _configuration.suppressesIncrementalRendering = NO;
        
    }
    return _configuration;
}
- (UIProgressView *)progressView {
    if (!_progressView) {
        _progressView = [[UIProgressView alloc] init];
        _progressView.progressTintColor = [UIColor orangeColor];
        _progressView.trackTintColor = [UIColor clearColor];
        _progressView.progress = 0;
    }
    return _progressView;
}
- (UIBarButtonItem *)backItem {
    if (_backItem == nil) {
        _backItem = [[UIBarButtonItem alloc] initWithTitle:@"返回" style:UIBarButtonItemStylePlain target:self action:@selector(backItemDidClicked)];
    }
    return _backItem;
}
- (UIBarButtonItem *)closeItem {
    if (!_closeItem) {
        _closeItem = [[UIBarButtonItem alloc] initWithTitle:@"关闭" style:UIBarButtonItemStylePlain target:self action:@selector(closeItemDidClicked)];
    }
    return _closeItem;
}

- (UIEdgeInsets)contentInset {
    return UIEdgeInsetsMake(_navigationBarHeight, 0, 0, 0);
}

@end
